#ifndef __PROCESSPOOL__
#define __PROCESSPOOL__

#include <iostream>
#include <unistd.h>
#include <vector>
#include <cstdlib>
#include <string>
#include "TaskManage.hpp"
#include <sys/wait.h>

const int process_num=5;
class Channel
{
public:
    Channel(int wfd,pid_t pid):_wfd(wfd),_pid(pid)
    {
        _name="文件描述符是："+std::to_string(_wfd)+"父进程id是"+std::to_string(_pid);
    }
    void Send(int code)
    {
        ssize_t ret=write(_wfd,&code,sizeof(code));
        (void)ret;
    }
    int getwfd(){return _wfd;}
    pid_t getpid(){return _pid;}
    std::string getname(){return _name;}
    void Close()
    {
        close(_wfd);
    }
    void Wait()
    {
       pid_t pid = waitpid(_pid,nullptr,0);
       (void)pid;
    }
    ~Channel(){}
private:
    int _wfd;//文件描述符
    pid_t _pid;//父进程id
    std::string _name;
};

class ChannelManage
{
public:
    ChannelManage():_next(0){}

    void CloseCh()
    {
        for(auto c:_ch)
        {
            c.Close();
            std::cout<<"关闭了"<<c.getname()<<std::endl;
        }
    }

    void waitch()
    {
        for(auto c:_ch)
        {
            c.Wait();
            std::cout<<"回收了"<<c.getname()<<std::endl;
        }
    }

    void closeandwait()
    {
        for(int i=_ch.size()-1;i>=0;i--)
        // for(int i=0;i<_ch.size();i++)
        {
            _ch[i].Close();
            std::cout<<"关闭了"<<_ch[i].getname()<<std::endl;
            _ch[i].Wait();
            std::cout<<"回收了"<<_ch[i].getname()<<std::endl;
        }
    }
    void InsertProcess(int fd,pid_t pid)
    {
        _ch.emplace_back(fd,pid);
    }

    void PrintInfo()
    {
        for(auto& channel:_ch)
        {
            std::cout<<"管道信息："<<channel.getname()<<channel.getpid()<<channel.getwfd()<<std::endl;
        }
    }

    //选择子进程
    Channel& Select()
    {
        Channel& co=_ch[_next++];
        _next%=_ch.size();
        return co;
    }

    void closeALL()
    {
        for(auto& ch:_ch)
        {
            ch.Close();
        }
    }
    ~ChannelManage(){}
private:
    std::vector<Channel> _ch;//管理管道
    int _next;
};

class ProcessPool
{
public:
    ProcessPool(int processnum):_process_num(processnum)
    {
        _tm.Push(PrintLog);
        _tm.Push(DownLoad);
        _tm.Push(UpLoad);
    }
    void work(int fd)
    {
        while(true)
        {
            int code=0;
            ssize_t ret = read(fd,&code,sizeof(code));
            if(ret>0)
            {
                if(ret!=sizeof(code))
                {
                    // std::cout<<"跳过"<<std::endl;
                    continue;
                }
                // std::cout<<"继续读取"<<std::endl;
                std::cout<<"子进程["<<getpid()<<"]收到了一个任务码"<<code<<std::endl;
                _tm.Executable(code);
            }
            //读到0说明写端关闭了
            else if(ret==0)
            {
                std::cout<<"子进程退出了"<<std::endl;
                break;
            }   
            else
            {
                std::cout<<"读取错误"<<std::endl;
                break;
            }
                     
        }
    }
    //建立进程
    bool CreateProcess()
    {
        for(int i=0;i<process_num;i++)
        {
            //创建管道
            int fd[2]={0};
            int ret=pipe(fd);
            if(ret<0)return false;

            std::cout<<"父进程id"<<getppid()<<std::endl;
            //创建子进程
            //父读子写
            pid_t ChildProcess=fork();
            if(ChildProcess<0)return false;
            //子进程创建成功,关闭读
            else if(ChildProcess==0)
            {
                //
                //两种方法：
                // 1.把close和wait封装成两个接口，在stop函数中调用接口即可
                // 2.倒着遍历_ch，此时不用调接口也可以
                // 3.让子进程把他所继承的哥哥的w端关闭即可
                _cm.closeALL();
                //子进程创建后，继承了父进程的文件描述符,并且二者指向同一个struct file
                //当任务读取完毕准备停止进程池时，如果从vector<Channel> _ch的第一个元素
                //Channel中存放的是子进程的相关信息，从首个子进程开始关闭，首个子进程继承了
                //的是父进程的文件描述符，关闭后就阻塞在父进程的读
                //倒着从_ch的最后一个开始遍历关闭就可以
                //0-r 1-w
                close(fd[1]);
                //通过管道实现进程间通信
                work(fd[0]);
                close(fd[0]);
                exit(0);
            }
            else
            {
                close(fd[0]);
                _cm.InsertProcess(fd[1],ChildProcess);
            }
            
        }
        return true;
    }
    void Print()
    {
        _cm.PrintInfo();
    }
    //发送任务码让子进程执行
    void PushTask()
    {
        //为了保证每个子进程都有任务可做，采用轮询策略选择当前执行人物的子进程
        Channel& co=_cm.Select();
        std::cout<<"选择了"<<co.getname()<<"号进程"<<std::endl;

        //产生任务码
        int n=_tm.Taskcode();

        co.Send(n);
        std::cout<<"发送了的任务码是"<<n<<std::endl;

    }
    void Stop()
    {
        // _cm.CloseCh();
        // _cm.waitch();
        //倒着关
        // _cm.closeandwait();//等待和close写在同一个函数内会阻塞
        
        //让父进程一人指向所有管道W端

    }
    ~ProcessPool()
    {}

private:
    int _process_num;
    ChannelManage _cm;
    TaskManage _tm;
};


#endif